/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package botobjects;

import interfaces.BotObject;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import main.Constants;

import org.apache.log4j.Logger;

import output.OutputTypeEnum;
import tools.StringTools;
import database.DBConnectionFactory;

/**
 * Represents a command
 * 
 * 
 */
public class Command implements BotObject, Serializable {
   private static final long serialVersionUID = 2689093756021383598L;

   /**
    * Removes the specified command
    * 
    * @param args
    * @return true if the command is successfully deleted
    */
   public static boolean deleteFromDB(final String... args) {
	  boolean out = false;
	  if (args.length < 1)
		 return out;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM commands WHERE name = ?");
		 ps.setString(1, args[0]);
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the specified command
    * 
    * @param name
    * @return Command object. Returns null if no command is found
    */
   public static Command getCommand(final String name) {
	  if (name == null)
		 return null;
	  Command out = null;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM commands WHERE " + "name = ?");
		 ps.setString(1, name);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			out = new Command(rs.getString("name"), rs.getString("aliases"), rs.getString("help"), rs.getString("syntax"),
				  rs.getString("cmdtype"), rs.getString("classname"), rs.getString("classurl"), rs.getInt("priority"),
				  rs.getBoolean("bypassantispam"), rs.getBoolean("publicaccess"), OutputTypeEnum.fromString(rs
						.getString("delivery")));
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns a list of all commands
    * 
    * @param args
    *           May define a specific group of commands to limit the results to
    * @return List of Command objects
    */
   public static List<Command> getCommands(final String... args) {
	  List<Command> out = new LinkedList<Command>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 if (args.length == 1) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM commands WHERE cmdtype = ?");
			ps.setString(1, args[0]);
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM commands");
		 }
		 rs = ps.executeQuery();

		 while (rs.next()) {
			out.add(new Command(rs.getString("name"), rs.getString("aliases"), rs.getString("help"), rs.getString("syntax"), rs
				  .getString("cmdtype"), rs.getString("classname"), rs.getString("classurl"), rs.getInt("priority"), rs
				  .getBoolean("bypassantispam"), rs.getBoolean("publicaccess"), OutputTypeEnum.fromString(rs
				  .getString("delivery"))));
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private String name = "";
   private String aliases = "";
   private String help = "";
   private String syntax = "";
   private String area = "";
   private String className = "";
   private String classURL = "";
   private int priority = 0;

   private boolean bypassAntiSpam = false;

   private boolean publicAccess = false;

   private OutputTypeEnum delivery = null;

   public Command(final String name, final String aliases, final String help, final String syntax, final String area,
		 final String className, final String classURL, final int priority, final boolean bypassAntiSpam,
		 final boolean publicAccess, final OutputTypeEnum delivery) {
	  this.name = name;
	  this.aliases = aliases;
	  this.help = help;
	  this.syntax = syntax;
	  this.area = area;
	  this.className = className;
	  this.classURL = classURL;
	  this.priority = priority;
	  this.bypassAntiSpam = bypassAntiSpam;
	  this.publicAccess = publicAccess;
	  this.delivery = delivery;
   }

   public String getAliases() {
	  return aliases;
   }

   public String getArea() {
	  return area;
   }

   public String getClassName() {
	  return className;
   }

   public String getClassURL() {
	  return classURL;
   }

   public OutputTypeEnum getDelivery() {
	  return delivery;
   }

   public String getHelp() {
	  return help;
   }

   @Override
   public List<String> getIRCOutput(final int outputType, final String... args) {
	  List<String> out = new LinkedList<String>();
	  if (StringTools.isNullOrEmpty(getName()) || getSyntax() == null || getHelp() == null || getAliases() == null)
		 return out;
	  if (outputType == Constants.COMMAND_GET_SYNTAX) {
		 out.add(getName() + " syntax: " + getSyntax());
	  } else if (outputType == Constants.COMMAND_GET_HELP) {
		 out.add(getName() + " - " + getHelp());
	  } else if (outputType == Constants.COMMAND_GET_ALIASES) {
		 out.add(getName() + " aliases: " + getAliases());
	  }
	  return out;
   }

   public String getName() {
	  return name;
   }

   public int getPriority() {
	  return priority;
   }

   @Override
   public Map<String, Object> getRPCOutput(final int... includes) {
	  Map<String, Object> out = new HashMap<String, Object>();
	  if (StringTools.isNullOrEmpty(getName()) || getSyntax() == null || getHelp() == null || getAliases() == null
			|| StringTools.isNullOrEmpty(getClassName()) || StringTools.isNullOrEmpty(getClassURL()))
		 return out;
	  out.put("Name", getName());
	  out.put("Aliases", Arrays.asList(aliases.split(",")));
	  out.put("Help", getHelp());
	  out.put("Syntax", getSyntax());
	  out.put("Area", getArea());
	  out.put("Class Name", getClassName());
	  out.put("Class URL", getClassURL());
	  out.put("Priority", getPriority());
	  out.put("Bypass Anti-Spam", isBypassAntiSpam());
	  out.put("Public Access", isPublicAccess());
	  return out;
   }

   public String getSyntax() {
	  return syntax;
   }

   public boolean isBypassAntiSpam() {
	  return bypassAntiSpam;
   }

   public boolean isPublicAccess() {
	  return publicAccess;
   }

   @Override
   public boolean saveToDB() {
	  boolean out = false;
	  if (StringTools.isNullOrEmpty(getName()) || getSyntax() == null || getHelp() == null || getAliases() == null
			|| StringTools.isNullOrEmpty(getClassName()) || StringTools.isNullOrEmpty(getClassURL()))
		 return out;
	  PreparedStatement ps = null;
	  try {
		 deleteFromDB(getName());

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("INSERT INTO commands " + "VALUES(?,?,?,?,?,?,?,?,?,?,?)");
		 ps.setString(1, getName());
		 ps.setString(2, getAliases());
		 ps.setInt(3, getPriority());
		 ps.setString(4, getClassName());
		 ps.setString(5, getClassURL());
		 ps.setString(6, getSyntax());
		 ps.setString(7, getHelp());
		 ps.setString(8, getArea());
		 ps.setBoolean(9, isBypassAntiSpam());
		 ps.setBoolean(10, isPublicAccess());
		 ps.setString(11, getDelivery().toString());
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public void setAliases(final String aliases) {
	  this.aliases = aliases;
   }

   public void setArea(final String area) {
	  this.area = area;
   }

   public void setBypassAntiSpam(final boolean bypassAntiSpam) {
	  this.bypassAntiSpam = bypassAntiSpam;
   }

   public void setClassName(final String className) {
	  this.className = className;
   }

   public void setClassURL(final String classURL) {
	  this.classURL = classURL;
   }

   public void setDelivery(final OutputTypeEnum delivery) {
	  this.delivery = delivery;
   }

   public void setHelp(final String help) {
	  this.help = help;
   }

   public void setPriority(final int priority) {
	  this.priority = priority;
   }

   public void setPublicAccess(final boolean publicAccess) {
	  this.publicAccess = publicAccess;
   }

   public void setSyntax(final String syntax) {
	  this.syntax = syntax;
   }
}
